package lab.anoper.juc.condition;

import lab.anoper.juc.utils.ThreadUtils;

import java.util.ArrayList;
import java.util.List;
import java.util.Random;
import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.ReentrantLock;

/**
 * @author 闫家洪（yanjiahong@vcredit.com）
 * @since 2024/12/12
 */
public class ProducerCustomer {
    private final int MAX_CACHE = 10;
    private final Random random = new Random();
    private final List<Bread> cache = new ArrayList<>(10);
    private final ReentrantLock lock = new ReentrantLock(true);
    private final Condition availCnd = lock.newCondition();
    private final Condition fullCnd = lock.newCondition();

    private boolean stopFlag = false;

    public void produce() throws Exception {
        while (!stopFlag) {
            lock.lock();
            try {
                if (cache.size() >= MAX_CACHE) {
                    System.out.printf("%s 生产者等待：缓冲区满\r\n", Thread.currentThread().getName());
                    fullCnd.await();
                } else {
                    ThreadUtils.randSleep(1000);
                    Bread bread = new Bread();
                    cache.add(bread);
                    System.out.printf("%s 生产者生产了产品 %s\n", Thread.currentThread().getName(), bread);
                    availCnd.signalAll();
                }
            } finally {
                lock.unlock();
            }
        }
    }

    public void consume() throws Exception {
        while (!stopFlag) {
            lock.lock();
            try {
                if (cache.size() == 0) {
                    System.out.printf("%s 消费者等待：缓冲区空\n", Thread.currentThread().getName());
                    availCnd.await();
                } else {
                    ThreadUtils.randSleep(1000);
                    Bread bread = cache.remove(0);
                    System.out.printf("%s 消费者消费了产品 %s\n", Thread.currentThread().getName(), bread);
                    fullCnd.signalAll();
                }
            } finally {
                lock.unlock();
            }
        }
    }

    public static void main(String[] args) throws Exception {
        final ProducerCustomer pc = new ProducerCustomer();
        for (int i = 0; i < 5; i++) {
            new Thread(() -> {
                try {
                    pc.produce();
                } catch (Exception e) {
                    throw new RuntimeException(e);
                }
            }).start();
        }

        for (int i = 0; i < 10; i++) {
            new Thread(() -> {
                try {
                    pc.consume();
                } catch (Exception e) {
                    throw new RuntimeException(e);
                }
            }).start();
        }

        Thread.sleep(100 * 1000);
        pc.stopFlag = true;
    }

    static class Bread {

    }
}











